#include "SocketIO.hpp"
#include "header.h"
#include <errno.h>

namespace wd
{

int SocketIO::recvn(char * buff , int len)
{
    int left = len;
    char * pbuf = buff;

    while(left > 0)
    {
        int ret = recv(_fd , pbuf , left , 0);

        if(ret == -1 && errno == EINTR)
        {
            continue;
        }
        else if(ret == -1)
        {
            perror("recv");
        }
        else if(ret == 0)
        {
            return len - left;
        }
        else 
        {
            left -= ret;
            pbuf += ret;
        }
    }

    return len;
}

int SocketIO::sendn(const char * buff , int len)
{
    int left = len;
    const char * pbuf = buff;

    while(left > 0)
    {
        int ret = send(_fd , pbuf , left , 0);

        if(ret < 0)
        {
            perror("send");

            return ret;
        }
        else
        {
            left -= ret;
            pbuf += ret;
        }
    }

    return len;
}

// maxlen : 表示一行最大的字节数
int SocketIO::readline(char * buff , int maxlen)
{
    // 获取的是一行数据，'\n' 是作为消息的边界而出现的
    int left = maxlen - 1;
    char * pbuf = buff;
    // 表示读取的总的字节数
    int total = 0;

    while(left > 0)
    {
        int ret = recvPeek(pbuf , left);

        // 查找"\n"
        for(int i = 0 ; i < ret ; ++i)
        {
            // 找到了'\n'
            if(pbuf[i] == '\n')
            {
                // 表示包含了 \n 的字节数
                int sz = i + 1;
                ret = recvn(pbuf , sz);
                total += ret;
                pbuf[i] = '\0';

                return total;
            }
        }

        // 这一次没有找到'\n' ,从内核接收缓冲区中移走
        ret = recvn(pbuf , ret);
        left -= ret;
        pbuf += ret;
        total += ret;
    }

    // 没有找到'\n'
    buff[maxlen - 1] = '\0';

    return maxlen - 1;
}

int SocketIO::recvPeek(char * buff , int maxlen) const
{
    int ret = 0;

    do
    {
        ret = recv(_fd , buff , maxlen , MSG_PEEK);
    }
    while(ret == -1 && errno == EINTR);

    if(ret < 0)
    {
        perror("recv");
    }

    return ret;
}

} // end of namespace wd
